#include "callstack.h"

#ifdef ENABLE_CALLSTACK

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ENABLE_FORWARD
#define ENABLE_BACKWARD

#define WRITE_LOG_FILE

#ifdef WRITE_LOG_FILE
#define stderr fp
FILE *fp = NULL;
#endif


static struct callstack *s = NULL;
static int created_flag = 0;

void new_callstack(int size)
{
	if(created_flag)
		return;
#ifdef WRITE_LOG_FILE
	fp = fopen("callstack.log","w");
#endif
	s=(struct callstack *)malloc(sizeof(struct callstack));
	if(s)
	{
		memset(s, 0, sizeof(struct callstack));
		s->item = (struct code_info *)malloc(sizeof(struct code_info)*size);
		memset(s->item, 0, sizeof(struct code_info)*size);
		//stack_size = size;
		s->size = size;
		created_flag = 1;
	}
}
void delete_callstack()
{
	if(s)
	{
		if(s->item)
		{
			memset(s->item, 0, sizeof(struct code_info)*(s->size));
			//stack_size = 0;
			free(s->item);
		}
		memset(s, 0, sizeof(struct callstack));
		free(s);
		s = NULL;
		created_flag = 0;
	}
#ifdef WRITE_LOG_FILE
	if(fp)
		fclose(fp);
#endif
}
struct code_info new_node(char *func_name, int line_num, int flag)
{
	int width;
	int i;
	width=strlen(func_name);
	if(width>64)
		width = 64;
	struct code_info temp;
	memset(&temp, 0, sizeof(struct code_info));
	memcpy(&(temp.name[0]), func_name, width);
	temp.line = line_num;
#ifdef ENABLE_FORWARD
	for(i=0;i<(int)(s->top-flag);i++)
		fprintf(stderr,"    ");
	if(flag)
		//fprintf(stderr,"(%03d+) %d\n", s->top, line_num);
		fprintf(stderr,"{ %d\n", line_num);
	else
		//fprintf(stderr,"{ (%03d) %s,%d\n", s->top, func_name, line_num);
		fprintf(stderr,"{ %s,%d\n", func_name, line_num);
#endif
	return temp;
}
void delete_node(struct code_info *node, int line_num,int flag)
{
	if(node)
	{
#ifdef ENABLE_BACKWARD
		int i;
		for(i=0;i<(int)(s->top-flag);i++)
			fprintf(stderr,"    ");
		if(flag)
			//fprintf(stderr,"(%03d-) %d at %d\n", s->top, node->line, line_num);
			fprintf(stderr,"} %d\n", line_num);
		else
			//fprintf(stderr,"} (%03d) %s,%d at %d\n", s->top, node->name, node->line, line_num);
			fprintf(stderr,"} %s,%d at %d\n", node->name, node->line, line_num);
#endif
	}
}
void callstack_push(char *func_name, int line_num)
{
	int top;
	int info_size = sizeof(struct code_info);
	struct code_info *tmp;
	int flag = 0;
	top = s->top;
	//if(top == stack_size)
	if(top == s->size)
		return;
	if(top>0)
	{
		if(strcmp(func_name, s->item[top-1].name)==0)
			flag = 1;
	}
	s->item[top] = new_node(func_name, line_num, flag);
	
	top++;
	s->top = top;
}

void callstack_pop(int line_num)
{
	int top;
	int info_size = sizeof(struct code_info);
	int flag = 0;
	top=s->top;
	if(top == 0)
		return;
	
	
	top--;
	s->top = top;
	if(top>0)
	{
		if(strcmp(s->item[top].name, s->item[top-1].name)==0)
			flag = 1;
	}
	delete_node(&(s->item[top]), line_num, flag);
}

void show_item_info(const int idx)
{
	if(idx < 0 || (idx > (s->top-1)))
		return;
	fprintf(stderr,"(%03d) %s,%d\n", idx, 
		s->item[idx].name,
		s->item[idx].line);
}

void show_last_item(const int num)
{
	int i;
	for(i=0;i<num;i++)
	{
		show_item_info(s->top-i-1);
	}
}

void show_all_item()
{
	int times = s->top;
	fprintf(stderr, "stack items=%d\n", times);
	show_last_item(times);
}
#endif
